package com.yuelao.yuelao_backend.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuelao.yuelao_backend.common.BizException;
import com.yuelao.yuelao_backend.common.ErrorCode;
import com.yuelao.yuelao_backend.dto.CommentDTO;
import com.yuelao.yuelao_backend.dto.PostDTO;
import com.yuelao.yuelao_backend.dto.request.AddCommentRequest;
import com.yuelao.yuelao_backend.dto.request.AddPostRequest;
import com.yuelao.yuelao_backend.entity.Comment;
import com.yuelao.yuelao_backend.entity.Post;
import com.yuelao.yuelao_backend.entity.PostLike;
import com.yuelao.yuelao_backend.entity.Topic;
import com.yuelao.yuelao_backend.entity.User;
import com.yuelao.yuelao_backend.entity.json.CommentItem;
import com.yuelao.yuelao_backend.entity.json.InteractionData;
import com.yuelao.yuelao_backend.entity.json.LikeItem;
import com.yuelao.yuelao_backend.entity.json.MediaItem;
import com.yuelao.yuelao_backend.mapper.CommentMapper;
import com.yuelao.yuelao_backend.mapper.PostLikeMapper;
import com.yuelao.yuelao_backend.mapper.PostMapper;
import com.yuelao.yuelao_backend.service.AchievementService;
import com.yuelao.yuelao_backend.service.PostService;
import com.yuelao.yuelao_backend.service.TopicService;
import com.yuelao.yuelao_backend.service.UserFollowService;
import com.yuelao.yuelao_backend.service.UserService;
import com.yuelao.yuelao_backend.util.UserContextUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class PostServiceImpl extends ServiceImpl<PostMapper, Post> implements PostService {

    @Resource
    private UserService userService;

    @Resource
    private CommentMapper commentMapper;

    @Resource
    private PostLikeMapper postLikeMapper;
    
    @Resource
    private AchievementService achievementService;

    @Resource
    private UserFollowService userFollowService;

    @Resource
    private TopicService topicService;

    @Override
    public List<PostDTO> getPosts(String type, int pageNum, int pageSize, BigDecimal latitude, BigDecimal longitude) {
        Page<Post> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Post::getStatus, 1);

        if ("recommend".equalsIgnoreCase(type)) {
            // 推荐逻辑：可以基于用户兴趣、活跃度、地理位置等，这里简化为按创建时间倒序
            queryWrapper.orderByDesc(Post::getCreatedAt);
        } else if ("follow".equalsIgnoreCase(type)) {
            // 关注逻辑：需要获取当前用户关注的人的动态，这里简化为按创建时间倒序
            // TODO: 实际需要结合用户关注关系表
            queryWrapper.orderByDesc(Post::getCreatedAt);
        } else if ("nearby".equalsIgnoreCase(type)) {
            if (latitude == null || longitude == null) {
                throw new BizException(ErrorCode.PARAMS_ERROR, "获取附近动态需要提供经纬度");
            }
            // 附近逻辑：根据经纬度计算距离，这里简化为按创建时间倒序
            // TODO: 实际需要复杂的地理空间查询
            queryWrapper.isNotNull(Post::getLatitude).isNotNull(Post::getLongitude)
                    .orderByDesc(Post::getCreatedAt);
        } else {
            throw new BizException(ErrorCode.PARAMS_ERROR, "不支持的动态类型: " + type);
        }

        Page<Post> postPage = page(page, queryWrapper);
        return convertToPostDTOList(postPage.getRecords());
    }

    @Override
    public List<PostDTO> getNearbyPosts(BigDecimal latitude, BigDecimal longitude) {
        if (latitude == null || longitude == null) {
            throw new BizException(ErrorCode.PARAMS_ERROR, "获取附近动态需要提供经纬度");
        }
        // 实际应用中，这里会进行复杂的地理空间查询，例如使用MySQL的ST_Distance_Sphere函数或GeoHash
        // 考虑到简化，这里仅返回所有动态，并模拟距离
        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Post::getStatus, 1)
                .isNotNull(Post::getLatitude)
                .isNotNull(Post::getLongitude)
                .orderByDesc(Post::getCreatedAt); // 简单排序

        List<Post> posts = list(queryWrapper);
        List<PostDTO> dtoList = convertToPostDTOList(posts);
        // 模拟距离
        dtoList.forEach(dto -> dto.setLocation("附近 " + (int)(Math.random() * 10) + "km"));
        return dtoList;
    }

    @Override
    public List<CommentDTO> getComments(Long postId) {
        Post post = getById(postId);
        if (post == null) {
            throw new BizException(ErrorCode.NOT_FOUND_ERROR, "动态不存在");
        }

        // 查询该帖子的所有评论（包括顶级评论和回复）
        LambdaQueryWrapper<Comment> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Comment::getPostId, postId)
                .eq(Comment::getStatus, 1)
                .orderByAsc(Comment::getCreatedAt);
        
        List<Comment> allComments = commentMapper.selectList(queryWrapper);
        
        if (CollectionUtils.isEmpty(allComments)) {
            return new ArrayList<>();
        }

        // 将所有评论分为顶级评论和回复
        List<Comment> topLevelComments = allComments.stream()
                .filter(comment -> comment.getParentId() == null)
                .collect(Collectors.toList());
        
        List<Comment> replies = allComments.stream()
                .filter(comment -> comment.getParentId() != null)
                .collect(Collectors.toList());

        // 转换顶级评论为 DTO 并组织回复
        return topLevelComments.stream()
                .map(comment -> convertCommentToDTO(comment, replies))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public boolean likePost(Long postId, Long userId) {
        Post post = getById(postId);
        if (post == null) {
            throw new BizException(ErrorCode.NOT_FOUND_ERROR, "动态不存在");
        }

        // 查询 post_likes 表，检查是否已点赞
        LambdaQueryWrapper<PostLike> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(PostLike::getPostId, postId)
                .eq(PostLike::getUserId, userId);
        PostLike existingLike = postLikeMapper.selectOne(queryWrapper);

        if (existingLike != null) {
            // 已点赞，取消点赞
            postLikeMapper.deleteById(existingLike.getId());
            // 减少点赞数
            if (post.getLikeCount() > 0) {
                post.setLikeCount(post.getLikeCount() - 1);
            }
        } else {
            // 未点赞，添加点赞
            PostLike newLike = new PostLike();
            newLike.setPostId(postId);
            newLike.setUserId(userId);
            newLike.setCreatedAt(LocalDateTime.now());
            postLikeMapper.insert(newLike);
            // 增加点赞数
            post.setLikeCount(post.getLikeCount() + 1);
        }

        post.setUpdatedAt(LocalDateTime.now());
        return updateById(post);
    }

    @Override
    @Transactional
    public boolean commentPost(Long postId, Long userId, AddCommentRequest request) {
        Post post = getById(postId);
        if (post == null) {
            throw new BizException(ErrorCode.NOT_FOUND_ERROR, "动态不存在");
        }

        InteractionData interactions = Optional.ofNullable(post.getInteractions()).orElse(new InteractionData());
        List<CommentItem> comments = Optional.ofNullable(interactions.getComments()).orElse(new ArrayList<>());

        CommentItem newComment = new CommentItem();
        newComment.setUserId(userId);
        newComment.setContent(request.getContent());
        newComment.setTime(LocalDateTime.now());
        newComment.setReplies(new ArrayList<>()); // 初始化回复列表

        if (request.getParentCommentId() != null) {
            // 回复评论
            Optional<CommentItem> parentCommentOpt = findCommentById(comments, request.getParentCommentId());
            if (parentCommentOpt.isEmpty()) {
                throw new BizException(ErrorCode.NOT_FOUND_ERROR, "回复的评论不存在");
            }
            CommentItem parentComment = parentCommentOpt.get();
            // 如果指定了目标用户ID，则设置（用于@某人）
            if (request.getTargetUserId() != null) {
                newComment.setTargetUserId(request.getTargetUserId());
            }
            parentComment.getReplies().add(newComment);
        } else {
            // 直接评论帖子（一级评论）
            comments.add(newComment);
        }

        interactions.setComments(comments);
        post.setCommentCount(post.getCommentCount() + 1);
        post.setUpdatedAt(LocalDateTime.now());

        return updateById(post);
    }

    @Override
    @Transactional
    public boolean addPost(Long userId, AddPostRequest request) {
        User user = userService.getById(userId);
        if (user == null) {
            throw new BizException(ErrorCode.NOT_FOUND_ERROR, "发布用户不存在");
        }

        Post post = new Post();
        post.setUserId(userId);
        post.setContent(request.getContent());
        post.setLocation(request.getLocation());
        post.setLatitude(request.getLatitude());
        post.setLongitude(request.getLongitude());
        post.setMedia(request.getMedia());
        post.setLikeCount(0);
        post.setCommentCount(0);
        post.setViewCount(0);
        post.setStatus(1); // 1-正常
        post.setCreatedAt(LocalDateTime.now());
        post.setUpdatedAt(LocalDateTime.now());

        boolean result = save(post);
        
        // 检查发帖相关成就
        if (result) {
            achievementService.checkPostAchievements(userId);
            
            // 检查特殊类型帖子成就
            if (post.getImages() != null && !post.getImages().isEmpty()) {
                // 带图发帖成就
                if (post.getImages().size() >= 3) {
                    // 多图发帖成就
                    checkMultiImagePostAchievement(userId);
                } else {
                    // 单图发帖成就
                    checkImagePostAchievement(userId);
                }
            }
            
            if (post.getLocation() != null && !post.getLocation().isEmpty()) {
                // 带位置发帖成就
                checkLocationPostAchievement(userId);
            }
            
            if (post.getVideoUrl() != null && !post.getVideoUrl().isEmpty()) {
                // 视频动态成就
                checkVideoPostAchievement(userId);
            }
            
            if (post.getContent() != null && post.getContent().length() >= 100) {
                // 长文动态成就
                checkLongPostAchievement(userId);
            }
            
            if (post.getTopicId() != null) {
                // 话题发帖成就
                checkTopicPostAchievement(userId);
            }
        }
        
        return result;
    }
    
    /**
     * 检查多图发帖成就
     */
    private void checkMultiImagePostAchievement(Long userId) {
        // 查询用户发布的多图动态数量
        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Post::getUserId, userId)
                .isNotNull(Post::getImages)
                .eq(Post::getStatus, 1);
        
        List<Post> posts = list(queryWrapper);
        long multiImageCount = posts.stream()
                .filter(post -> post.getImages() != null && post.getImages().size() >= 3)
                .count();
        
        achievementService.checkAchievementProgress(userId, "multi_image_post", (int) multiImageCount);
    }
    
    /**
     * 检查带图发帖成就
     */
    private void checkImagePostAchievement(Long userId) {
        // 查询用户发布的带图动态数量
        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Post::getUserId, userId)
                .isNotNull(Post::getImages)
                .eq(Post::getStatus, 1);
        
        long imageCount = count(queryWrapper);
        achievementService.checkAchievementProgress(userId, "image_post", (int) imageCount);
    }
    
    /**
     * 检查带位置发帖成就
     */
    private void checkLocationPostAchievement(Long userId) {
        // 查询用户发布的带位置动态数量
        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Post::getUserId, userId)
                .isNotNull(Post::getLocation)
                .eq(Post::getStatus, 1);
        
        long locationCount = count(queryWrapper);
        achievementService.checkAchievementProgress(userId, "location_post", (int) locationCount);
    }
    
    /**
     * 检查视频动态成就
     */
    private void checkVideoPostAchievement(Long userId) {
        // 查询用户发布的视频动态数量
        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Post::getUserId, userId)
                .isNotNull(Post::getVideoUrl)
                .eq(Post::getStatus, 1);
        
        long videoCount = count(queryWrapper);
        achievementService.checkAchievementProgress(userId, "video_post", (int) videoCount);
    }
    
    /**
     * 检查长文动态成就
     */
    private void checkLongPostAchievement(Long userId) {
        // 查询用户发布的长文动态数量
        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Post::getUserId, userId)
                .isNotNull(Post::getContent)
                .ge(Post::getContent, 100)
                .eq(Post::getStatus, 1);
        
        long longPostCount = count(queryWrapper);
        achievementService.checkAchievementProgress(userId, "long_post", (int) longPostCount);
    }
    
    /**
     * 检查话题发帖成就
     */
    private void checkTopicPostAchievement(Long userId) {
        // 查询用户在不同话题发布的动态数量
        LambdaQueryWrapper<Post> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Post::getUserId, userId)
                .isNotNull(Post::getTopicId)
                .eq(Post::getStatus, 1);
        
        List<Post> topicPosts = list(queryWrapper);
        long distinctTopicCount = topicPosts.stream()
                .map(Post::getTopicId)
                .distinct()
                .count();
        
        // 检查不同话题发帖成就
        achievementService.checkAchievementProgress(userId, "diverse_topic", (int) distinctTopicCount);
        
        // 检查话题发帖数量成就
        long topicPostCount = topicPosts.size();
        achievementService.checkAchievementProgress(userId, "topic_post", (int) topicPostCount);
    }

    @Override
    public List<PostDTO> convertToPostDTOList(List<Post> posts) {
        if (CollectionUtils.isEmpty(posts)) {
            return new ArrayList<>();
        }

        // 1. 收集所有需要查询的ID
        Set<Long> userIds = posts.stream()
                .map(Post::getUserId)
                .collect(Collectors.toSet());
        Set<Long> topicIds = posts.stream()
                .map(Post::getTopicId)
                .filter(id -> id != null)
                .collect(Collectors.toSet());

        // 2. 批量查询用户信息
        Map<Long, User> userMap = Collections.emptyMap();
        if (!userIds.isEmpty()) {
            List<User> users = userService.listByIds(userIds);
            userMap = users.stream()
                    .collect(Collectors.toMap(User::getId, Function.identity()));
        }

        // 3. 批量查询话题信息
        Map<Long, Topic> topicMap = Collections.emptyMap();
        if (!topicIds.isEmpty()) {
            List<Topic> topics = topicService.listByIds(topicIds);
            topicMap = topics.stream()
                    .collect(Collectors.toMap(Topic::getId, Function.identity()));
        }

        // 4. 获取当前用户ID并批量查询关注关系
        Set<Long> followedUserIds = Collections.emptySet();
        try {
            Long currentUserId = UserContextUtil.getCurrentUserId();
            if (currentUserId != null) {
                final Long finalCurrentUserId = currentUserId;
                // 过滤掉当前用户自己
                Set<Long> otherUserIds = userIds.stream()
                        .filter(id -> !id.equals(finalCurrentUserId))
                        .collect(Collectors.toSet());
                if (!otherUserIds.isEmpty()) {
                    followedUserIds = userFollowService.getFollowedUserIds(currentUserId, otherUserIds);
                }
            }
        } catch (Exception e) {
            // 用户未登录，忽略
        }

        // 5. 转换为DTO
        final Map<Long, User> finalUserMap = userMap;
        final Map<Long, Topic> finalTopicMap = topicMap;
        final Set<Long> finalFollowedUserIds = followedUserIds;

        return posts.stream()
                .map(post -> convertToPostDTOWithCache(post, finalUserMap, finalTopicMap, finalFollowedUserIds))
                .collect(Collectors.toList());
    }

    /**
     * 使用缓存数据转换单个Post为PostDTO
     */
    private PostDTO convertToPostDTOWithCache(Post post, Map<Long, User> userMap,
            Map<Long, Topic> topicMap, Set<Long> followedUserIds) {
        PostDTO dto = new PostDTO();

        // 设置基础字段
        dto.setId(post.getId());
        dto.setUserId(post.getUserId());
        dto.setContent(post.getContent());
        dto.setLocation(post.getLocation());
        dto.setLatitude(post.getLatitude() != null ? post.getLatitude().doubleValue() : null);
        dto.setLongitude(post.getLongitude() != null ? post.getLongitude().doubleValue() : null);
        dto.setLikeCount(post.getLikeCount());
        dto.setCommentCount(post.getCommentCount());
        dto.setViewCount(post.getViewCount());
        dto.setCreatedAt(post.getCreatedAt());

        // 设置话题信息（从缓存获取）
        dto.setTopicId(post.getTopicId());
        if (post.getTopicId() != null) {
            Topic topic = topicMap.get(post.getTopicId());
            if (topic != null) {
                dto.setTopicName(topic.getName());
            }
        }

        // 转换图片和视频为 MediaItem 列表
        List<MediaItem> mediaList = new ArrayList<>();
        int sortOrder = 0;
        if (post.getImages() != null && !post.getImages().isEmpty()) {
            for (String imageUrl : post.getImages()) {
                MediaItem item = new MediaItem();
                item.setType("image");
                item.setUrl(imageUrl);
                item.setSortOrder(sortOrder++);
                mediaList.add(item);
            }
        }
        if (StringUtils.hasText(post.getVideoUrl())) {
            MediaItem item = new MediaItem();
            item.setType("video");
            item.setUrl(post.getVideoUrl());
            item.setSortOrder(sortOrder);
            mediaList.add(item);
        }
        dto.setMedia(mediaList.isEmpty() ? null : mediaList);

        // 获取用户信息（从缓存获取）
        User user = userMap.get(post.getUserId());
        if (user != null) {
            dto.setNickname(user.getNickname());
            dto.setAvatar(user.getAvatar());
            dto.setAge(user.getAge());
            dto.setGender(user.getGender());
            dto.setVip(user.getIsVip() != null && user.getIsVip());
        }

        // 设置关注状态（从缓存获取）
        dto.setFollowed(followedUserIds.contains(post.getUserId()));

        // 格式化时间
        dto.setTimeAgo(formatTimeAgo(post.getCreatedAt()));
        return dto;
    }

    @Override
    public PostDTO convertToPostDTO(Post post) {
        if (post == null) {
            return null;
        }
        // 单个转换时调用批量方法
        List<PostDTO> result = convertToPostDTOList(Collections.singletonList(post));
        return result.isEmpty() ? null : result.get(0);
    }

    private CommentDTO convertToCommentDTO(CommentItem commentItem, Long postUserId) {
        CommentDTO dto = new CommentDTO();
        BeanUtils.copyProperties(commentItem, dto);

        // 填充评论用户信息
        User commentUser = userService.getById(commentItem.getUserId());
        if (commentUser != null) {
            dto.setNickname(commentUser.getNickname());
            dto.setAvatar(commentUser.getAvatar());
        }

        // 填充回复目标用户信息
        if (commentItem.getTargetUserId() != null) {
            User targetUser = userService.getById(commentItem.getTargetUserId());
            if (targetUser != null) {
                dto.setTargetUserNickname(targetUser.getNickname());
            }
        }

        dto.setCreatedAt(commentItem.getTime());
        dto.setTimeAgo(formatTimeAgo(commentItem.getTime()));

        // 递归处理回复
        if (!CollectionUtils.isEmpty(commentItem.getReplies())) {
            dto.setReplies(commentItem.getReplies().stream()
                    .sorted(Comparator.comparing(CommentItem::getTime))
                    .map(reply -> convertToCommentDTO(reply, postUserId))
                    .collect(Collectors.toList()));
        }
        return dto;
    }

    private String formatTimeAgo(LocalDateTime dateTime) {
        if (dateTime == null) {
            return "";
        }
        LocalDateTime now = LocalDateTime.now();
        long minutes = ChronoUnit.MINUTES.between(dateTime, now);
        long hours = ChronoUnit.HOURS.between(dateTime, now);

        if (minutes < 1) {
            return "刚刚";
        } else if (minutes < 60) {
            return minutes + "分钟前";
        } else if (hours < 24) {
            return hours + "小时前";
        } else {
            // 超过24小时直接格式化日期
            return dateTime.format(java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
        }
    }

    /**
     * 递归查找评论
     */
    private Optional<CommentItem> findCommentById(List<CommentItem> comments, Long commentId) {
        if (CollectionUtils.isEmpty(comments)) {
            return Optional.empty();
        }
        for (CommentItem comment : comments) {
            if (comment.getId().equals(commentId)) {
                return Optional.of(comment);
            }
            if (!CollectionUtils.isEmpty(comment.getReplies())) {
                Optional<CommentItem> foundInReplies = findCommentById(comment.getReplies(), commentId);
                if (foundInReplies.isPresent()) {
                    return foundInReplies;
                }
            }
        }
        return Optional.empty();
    }

    /**
     * 将 Comment 实体转换为 CommentDTO（从真实的 comments 表）
     */
    private CommentDTO convertCommentToDTO(Comment comment, List<Comment> allReplies) {
        CommentDTO dto = new CommentDTO();
        dto.setId(comment.getId());
        dto.setUserId(comment.getUserId());
        dto.setContent(comment.getContent());
        dto.setCreatedAt(comment.getCreatedAt());
        dto.setTimeAgo(formatTimeAgo(comment.getCreatedAt()));

        // 填充评论用户信息
        User commentUser = userService.getById(comment.getUserId());
        if (commentUser != null) {
            dto.setNickname(commentUser.getNickname());
            dto.setAvatar(commentUser.getAvatar());
        }

        // 填充回复目标用户信息（如果是回复）
        if (comment.getReplyToUserId() != null) {
            dto.setTargetUserId(comment.getReplyToUserId());
            User targetUser = userService.getById(comment.getReplyToUserId());
            if (targetUser != null) {
                dto.setTargetUserNickname(targetUser.getNickname());
            }
        }

        // 查找该评论的所有回复
        List<Comment> directReplies = allReplies.stream()
                .filter(reply -> comment.getId().equals(reply.getParentId()))
                .collect(Collectors.toList());

        if (!CollectionUtils.isEmpty(directReplies)) {
            dto.setReplies(directReplies.stream()
                    .map(reply -> convertCommentToDTO(reply, allReplies))
                    .collect(Collectors.toList()));
        }

        return dto;
    }
}